/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package routefinder.implementation;

import java.util.Map;
import routefinder.City;
import routefinder.RouteFinder;
import routefinder.RouteFinderExtended;

/**
 * This class behaves as a facade to the Dijkstra Engine.
 * 
 * @author Lucas
 */
public class RouteFinderExtendedImpl implements RouteFinderExtended {

    private static RouteFinderExtendedImpl instance;
    private Dijkstra engine;
    private City previousStartCity;
    private IRoutesMap routesMap;

    private RouteFinderExtendedImpl() {
    }

    public static RouteFinderExtendedImpl getInstance() {
        if (instance == null) {
            instance = new RouteFinderExtendedImpl();
        }
        return instance;
    }

    /**
     * Sets the graph.
     *
     * @param routesMap
     */
    public void setRoutesMap(IRoutesMap routesMap) {
        this.routesMap = routesMap;
    }


    /**
     * @see RouteFinderExtended#getAllShortestRouteLengths(routefinder.City) 
     */
    public Map<City, Integer> getAllShortestRouteLengths(City startCity) {
        restartEngineWhenRequired(startCity);
        return engine.getShortestDistances();
    }

    /**
     * @see RouteFinder#getShortestRouteLength(routefinder.City, routefinder.City)
     */
    public int getShortestRouteLength(City startCity, City endCity) {
        Integer d = getAllShortestRouteLengths(startCity).get(endCity);
        return (d == null) ? -1 : d;
    }

    private City checkForExistingCity(City startCity) throws RouteFinderExcception {
        final Map<City, City> currentCities = routesMap.getCities();
        City existingCityReference = currentCities.get(startCity);
        if (existingCityReference == null) {
            throw new RouteFinderExcception("City " + startCity + " doesn't exist on this map");
        }
        return existingCityReference;
    }

    private void restartEngineWhenRequired(City startCity) {
        if (this.previousStartCity == null || !this.previousStartCity.equals(startCity)) {
            engine = new Dijkstra(routesMap);
            City existingCityReference = checkForExistingCity(startCity);
            engine.execute(existingCityReference, null);
            this.previousStartCity = existingCityReference;
        }
    }
}
